#!/usr/bin/python
#encoding:utf-8
'''
@license : Copyright@haohandata
@version : 1.0
@todo : created in 2020-3-16，兼容HDT设备
@author : wd
'''
import commands
import time
import sys
import os
import json
plugins_path = os.getenv('INSPECTOR_HOME') + '/plugins'
sys.path.append(plugins_path + '/common/')
import get_snmp_info
import tools
import get_ip_list
import threading
'''flags流量类型：1—1分钟的流量统计，2—5分钟的流量统计，3—历史总流量统计 
       totalFlags流量上报类型：0—只上报有流量统计的项；1—上报所有项；
       version 通信协议的版本号
'''
FLAGS = 2
TOTAL_FLAGS = 0
VERSION = '14.2'
LOGGER_FILE = 'probe_traffic_collect.log'
logger = tools.get_logger(LOGGER_FILE)
config_file = os.getenv('INSPECTOR_HOME') + '/conf/install.conf'
zmq_install_shell = os.getenv('INSPECTOR_HOME') + '/bin/zmq_install.sh'
utc_time = time.strftime('%s', time.localtime())
READER_VERSION = "TCR1.4"
GROUP_GE = [
    1, 17, 20, 33, 36, 49, 52, 65, 66, 81, 82, 97, 98, 113, 129, 145, 161, 273,
    289, 305
]
GROUP_TEN_GE = [
    177, 178, 180, 193, 209, 210, 212, 225, 241, 257, 194, 196, 4292, 4308
]
SOCKET_PORT = 6011
# PARAM_TYPE = [112, 113]
PARAM_TYPE = [121]
dev_map = {'1': 'KG1300', '2': 'KG2000', '3': 'KG2000E', '4': 'HDT5000'}


class get_probe_traffic(threading.Thread):
    def __init__(self, ip):
        threading.Thread.__init__(self)
        self.ip = ip

    def run(self):
        (status, output) = commands.getstatusoutput(
            'expect %s/collect/probe_traffic_collect.exp %s probe_traffic' %
            (plugins_path, self.ip))
        if status == 0:
            #print output
            for line in output.splitlines():
                l = line.strip().split(",")
                if len(l) >= 26:
                    time = int(l[0]) - int(l[0]) % 300
                    deviceid = l[1]
                    slotid = l[2]
                    linkid = l[3]
                    intftype = l[4]
                    LinkUniBiDir = l[5]
                    L_UpIntfStatus = l[6]
                    L_DnIntfStatus = l[7]
                    L_OptComm = l[8]
                    L_OptStatus = l[9]
                    L_UpPkt = (int(l[10]) << 32) + int(l[11])
                    L_DnPkt = (int(l[12]) << 32) + int(l[13])
                    L_UpByte = (int(l[14]) << 32) + int(l[15])
                    L_DnByte = (int(l[16]) << 32) + int(l[17])
                    I_BusUpPkt = (int(l[18]) << 32) + int(l[19])
                    I_BusDnPkt = (int(l[20]) << 32) + int(l[21])
                    I_BusUpByte = (int(l[22]) << 32) + int(l[23])
                    I_BusDnByte = (int(l[24]) << 32) + int(l[25])
                    if (READER_VERSION.upper() == 'TCR1.4'):
                        (l_up_intf_status, l_down_intf_status) = parseStatus14(
                            intftype, L_UpIntfStatus, L_DnIntfStatus)
                    else:
                        (l_up_intf_status, l_down_intf_status) = parseStatus15(
                            intftype, L_UpIntfStatus, L_DnIntfStatus)
                    print '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' % (
                        slotid, linkid, deviceid, l_up_intf_status,
                        l_down_intf_status, L_OptComm, L_OptStatus, L_UpPkt,
                        L_DnPkt, L_UpByte, L_DnByte, I_BusUpPkt, I_BusDnPkt,
                        I_BusUpByte, I_BusDnByte, time, intftype, LinkUniBiDir,
                        'probe_traffic'),


class hdt_probe_traffic(threading.Thread):
    def __init__(self, ip):
        threading.Thread.__init__(self)
        self.ip = ip
        self._build_socket_connect()

    def _build_socket_connect(self):
        import zmq
        try:
            context = zmq.Context()
            self.socket = context.socket(zmq.REQ)
            self.socket.connect("tcp://" + self.ip + ":" + str(SOCKET_PORT))
        except Exception as e:
            logger.info(e)

    def run(self):
        bytes_list = []
        for type in PARAM_TYPE:
            param = build_param(type)
            result = deal_data(self.socket, param)
            if result is not None and result['result'] and len(
                    result['result']) > 0:
                if result['type'] == 121:
                    bytes_list = result['result'][0]['statistics']
                # else:
                #     pkts_list = filter(lambda x: x['linkIndex'] != -1,
                #                        result['result'][0]['statistics'])
        hdt_print_result(bytes_list,self.ip)
        self.socket.close()

    # deal_data(self, socket, param)


def build_param(type):
    param = {
        "message": {
            "flags": FLAGS,
            "totalFlags": TOTAL_FLAGS
        },
        "operate": 2,
        "sequence": 0,
        "size": 1,
        "source": "HH-DNV",
        "type": type,
        "version": VERSION
    }
    return param


def deal_data(socket, param):
    try:
        socket.send(json.dumps(param))
    except IOError as e:
        logger.info(e)
    try:
        response = socket.recv()
        response_json = json.loads(response)
        if response_json['code'] == 200:
            return response_json
    except socket.timeout as e:
        logger.info(e)
    except socket.error as e:
        logger.info(e)


def hdt_print_result(all_list, ip):
    link_map = {}
    for link in all_list:
        slot_num = link['slotNum']
        link_index = link['linkIndex']
        key = str(slot_num) + '|' + str(link_index)
        if key not in link_map.keys():
            link_map[key] = link
        else:
            link_map[key]['upTotalBytes']= link_map[key]['upTotalBytes']+link['upTotalBytes']
            link_map[key]['dnTotalBytes']= link_map[key]['dnTotalBytes']+link['dnTotalBytes']
    device_map = get_device_id(ip)
    for link in link_map:
        slotid = link.split('|')[0]
        linkid = link.split('|')[1]
        time = utc_time
        deviceid = device_map[slotid]
        l_up_intf_status = "up"
        l_down_intf_status = "up"
        LinkUniBiDir = 1
        L_OptComm = 1
        L_OptStatus = 0
        # TODO 按时不取报文
        L_UpPkt = link_map[link].setdefault('upTotalPkts', 0)
        L_DnPkt = link_map[link].setdefault('dnTotalPkts', 0)
        L_UpByte = link_map[link].setdefault('upTotalBytes', 0)
        L_DnByte = link_map[link].setdefault('dnTotalBytes', 0)
        I_BusUpPkt = 0
        I_BusDnPkt = 0
        I_BusUpByte = 0
        I_BusDnByte = 0
        intftype = 255
        print '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' % (
            slotid, linkid, deviceid, l_up_intf_status, l_down_intf_status,
            L_OptComm, L_OptStatus, L_UpPkt, L_DnPkt, L_UpByte, L_DnByte,
            I_BusUpPkt, I_BusDnPkt, I_BusUpByte, I_BusDnByte, time, intftype,
            LinkUniBiDir, 'probe_traffic'),


def get_device_id(ip):
    device_map = {}
    board_map = {}
    (status,
     output) = get_snmp_info.get_snmp_info(ip,
                                           ".1.3.6.1.4.1.3470.8.8.1.1.27.1")
    if status == 0:
        tmp_list = output.splitlines()
        for line in tmp_list:
            if ".3470.8.8.1.1.27.1.3" in line:
                index = line.split('=')[0].strip().split('.')[-1].strip()
                if not index in board_map.keys():
                    board_map[index] = {'slot_id': 1, 'device_id': 0}
                slot_id = line.split(' ')[-1].strip()
                board_map[index]['slot_id'] = slot_id
            elif ".3470.8.8.1.1.27.1.11" in line:
                index = line.split('=')[0].strip().split('.')[-1].strip()
                device_id = line.split(' ')[-1].strip()
                board_map[index]['device_id'] = device_id
            else:
                pass
    for key in board_map:
        device_map[board_map[key]['slot_id']] = board_map[key]['device_id']

    return device_map


# TCR1.4版本的状态解析函数
def parseStatus14(intftype, L_UpIntfStatus, L_DnIntfStatus):
    l_up_intf_status = "down"
    l_down_intf_status = "down"
    int_intftype = int(intftype)
    if (int_intftype in GROUP_GE):
        t1 = int(L_UpIntfStatus) & 2
        if t1 == 0:
            l_up_intf_status = "down"
        else:
            l_up_intf_status = "up"
        t2 = int(L_DnIntfStatus) & 2
        if t2 == 0:
            l_down_intf_status = "down"
        else:
            l_down_intf_status = "up"
    elif (int_intftype in GROUP_TEN_GE):
        t1 = int(L_UpIntfStatus) & 128
        if t1 == 0:
            l_up_intf_status = "up"
        else:
            l_up_intf_status = "down"
        t2 = int(L_DnIntfStatus) & 128
        if t2 == 0:
            l_down_intf_status = "up"
        else:
            l_down_intf_status = "down"
    else:
        l_up_intf_status = "down"
        l_down_intf_status = "down"
    return (l_up_intf_status, l_down_intf_status)


# TCR1.5版本的状态解析函数
def parseStatus15(intftype, L_UpIntfStatus, L_DnIntfStatus):
    l_up_intf_status = "up"
    l_down_intf_status = "up"
    if (int(intftype) >= 11 and int(intftype) <= 16) or int(intftype) == 196:
        t1 = int(L_UpIntfStatus) & 128
        if t1 == 0:
            l_up_intf_status = "up"
        else:
            l_up_intf_status = "down"
        t2 = int(L_DnIntfStatus) & 128
        if t2 == 0:
            l_down_intf_status = "up"
        else:
            l_down_intf_status = "down"
    elif int(intftype) == 19:
        l_up_intf_status = "down"
        l_down_intf_status = "down"
    else:
        t1 = int(L_UpIntfStatus) & 2
        if t1 == 0:
            l_up_intf_status = "down"
        else:
            l_up_intf_status = "up"
        t2 = int(L_DnIntfStatus) & 2
        if t2 == 0:
            l_down_intf_status = "down"
        else:
            l_down_intf_status = "up"
    return (l_up_intf_status, l_down_intf_status)




# TODO 因为snmp不通时会导致30秒的超时，所以先改为从db中读取
def get_tma_type(ip):
    tma_type = ""
    try:
        (status, output) = get_snmp_info.get_snmp_info(
            ip, ".1.3.6.1.4.1.3470.8.8.1.1.28.0")
        if status == 0:
            tma_type = dev_map[output.split(" ")[-1].strip()]
    except UnboundLocalError:
        pass
    return tma_type


def install_zmq():
    cmd = 'sh ' + zmq_install_shell
    (status, output) = commands.getstatusoutput(cmd)
    if status != 0:
        logger.info(output)
        sys.exit(1)


if __name__ == '__main__':
    ip_list = get_ip_list.get_ip_list('TMA')
    # ip_list = ['10.10.20.181', '10.10.13.115']
    # ip_list=['10.10.20.181']
    tma_type_map = tools.get_tma_type_from_db()
    for ip in ip_list:
        # dev_type = get_tma_type(ip)
        if tma_type_map.has_key(ip):
            dev_type=tma_type_map[ip]
            if dev_type == 'HDT5000':
                (status,
                output) = commands.getstatusoutput('python -c "import zmq"')
                if status != 0:
                    install_zmq()
                bytes_list = []
                pkts_list = []
                thread = hdt_probe_traffic(ip)
                thread.start()
            else:
                thread = get_probe_traffic(ip)
                thread.start()